//
// Created by  tianweixing on 23/6/2025.
//

#ifndef MEMORY_POOL_H
#define MEMORY_POOL_H

namespace memory_pool {
#include <iostream>
#include <mutex>

#define MEMORY_POOL_NUM  64    // 内存池数量
#define SLOT_BASE_SIZE   8     // 槽位基础大小(字节)
#define MAX_SLOT_SIZE    512   // 最大槽位大小(字节)

struct slot {
    slot *next;
};

class memory_pool {
public:
    memory_pool(int block_size = 4096) {}
    ~memory_pool();

    void init(size_t);
    void *allocate();
    void deallocate(void*);
private:
    int block_size_; // 内存块的大小
    int slot_size_; // slot的大小
    slot* free_list_; // 空闲内存块链表
    slot* cur_unused_list_; // 当前未使用的第一个slot
    slot* first_block_; //内存池管理的首个实际的内存块
    slot* last_slot_; // 最后一个slot
    std::mutex mutex_for_freelist_; // 锁 用于管理空闲内存块链表
    std::mutex mutex_for_block_; // 锁 用于管理内存池
    void allocate_new_block();
    size_t pad_pointer(void* p, size_t align); // 对齐指针，保证为align的大小
};

class hash_bucket {
private:

public:
    // 构造函数用于初始化hash_bucket对象
    // 参数size表示桶的大小，默认值为MAX_SLOT_SIZE除以SLOT_BASE_SIZE的结果
    hash_bucket(int size = MAX_SLOT_SIZE / SLOT_BASE_SIZE) {}
    ~hash_bucket();
    void init_memory_pool();
    static memory_pool& get_memory_pool(size_t index);
    static void* use_memory(int size) {
        if (size < 0) {
            return nullptr;
        }
        if (size > MAX_SLOT_SIZE) {
            return malloc(size);
        }
        return get_memory_pool(((size + 7) / SLOT_BASE_SIZE) - 1 ).allocate();
    }
    static void free_memory(char *p, int size) {
        if (p == nullptr) {
            return;
        }
        if (size > MAX_SLOT_SIZE) {
            free(p);
        }
        get_memory_pool(((size + 7) / SLOT_BASE_SIZE) - 1 ).deallocate(p);
    }
	// 申请内存 新建元素 此处使用了模板 会自动根据传入的参数计算需要分配多少内存大小
    template<typename T, typename... Args>
    friend T* new_element(Args&&... args);
	// 删除元素
    template<typename T>
    friend void delete_element(T* p);
};


/**
 * 使用构造 placement new 和完美转发创建新元素
 * 
 * 本函数通过构造函数在指定内存位置上创建一个新对象，从而避免常规的内存分配过程
 * 它首先尝试从内存池中分配一块足够大的内存用于新对象，如果分配成功，则使用 placement new 和完美转发
 * 将参数转发给对象的构造函数，完成对象的构造过程
 * 
 * @tparam T 要创建的对象类型
 * @tparam Args 构造函数参数类型
 * @param args 构造函数参数
 * @return 返回新创建对象的指针，如果内存分配失败，则返回 NULL
 */
// 新建元素
template<typename T, typename... Args>
T* new_element(Args&&... args) {
    // 尝试从内存池中分配一块足够大的内存用于新对象
    T* p = static_cast<T*>(hash_bucket::use_memory(sizeof(T)));
    if (p == nullptr) {
        // 如果内存分配失败，返回 NULL
        return NULL;
    }
    // 使用 placement new 和完美转发将参数转发给对象的构造函数，完成对象的构造过程
    new (p) T(std::forward<Args>(args)...);
    return p;
}

// 删除元素
template<typename T>
void delete_element(T* p) {
    if (p == nullptr) {
        return;
    }
    p->~T();
    hash_bucket::free_memory(p, sizeof(T));
    p = nullptr;
}
};

#endif //MEMORY_POOL_H
